package org.yzh.web.controller;

import cn.hutool.core.util.HexUtil;
import io.swagger.v3.oas.annotations.Operation;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.yzh.commons.model.APICodes;
import org.yzh.commons.model.APIResult;
import org.yzh.commons.util.JsonUtils;
import org.yzh.protocol.basics.JTMessage;
import org.yzh.protocol.commons.JT808;
import org.yzh.protocol.t808.*;
import org.yzh.web.endpoint.MessageManager;
import org.yzh.web.model.entity.Device;
import org.yzh.web.service.IDeviceService;
import org.yzh.web.utils.CacheUtil;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("device")
public class JT808Controller {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private MessageManager messageManager;

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private CacheUtil cacheUtil;

//    @Operation(summary = "8107 查询终端属性")
//    @PostMapping("8107")
//    public Mono<APIResult<T0107>> T8107(@RequestBody JTMessage request) {
//        return messageManager.requestR(request.messageId(JT808.查询终端属性), T0107.class);
//    }

//    @Operation(summary = "8201 位置信息查询")
//    @PostMapping("8201")
//    public Mono<APIResult<T0201_0500>> T8201(@RequestBody JTMessage request) {
//        return messageManager.requestR(request.messageId(JT808.位置信息查询), T0201_0500.class);
//    }

    @Operation(summary = "8202 临时位置跟踪控制")
    @PostMapping("8202")
    public Mono<APIResult<T0001>> T8202(@RequestBody T8202 request) {
        return messageManager.requestR(request, T0001.class);
    }

    @Operation(summary = "8203 人工确认报警消息")
    @PostMapping("8203")
    public Mono<APIResult<T0001>> T8203(@RequestBody T8203 request) {
        return messageManager.requestR(request, T0001.class);
    }

    @Operation(summary = "8300 文本指令下发")
    @PostMapping("8300")
    public Mono<APIResult<T0001>> T8300(@RequestBody T8300 request) {
        String pre = "loc:";
        String content = request.getContent();
        if ("C".equals(content)){
            if (cacheUtil.hasKey(pre+request.getClientId())) {
                log.error("{} C location lt 30 seconds", request.getClientId());
                return Mono.just(new APIResult(APICodes.BusyLocationClient));
            }
            cacheUtil.add(pre+request.getClientId(), System.currentTimeMillis()+""
                    , 31, TimeUnit.SECONDS);
            if (log.isInfoEnabled())
                log.info("{} C location will send", request.getClientId());
        }
        if (request.getSign() == 8){
            String hex = HexUtil.encodeHexStr(content);
            log.info("utf8 hex: "+hex);
            if (hex.length() > 120) {
                log.error("{} hex gt 60 bytes", content);
                return Mono.just(new APIResult(APICodes.ContentGt60Byte));
            }
        }
        return messageManager.requestR(request, T0001.class);
    }

    @Operation(summary = "查询数据库记录")
    @GetMapping("location/{clientId}")
    public Mono<APIResult<Object>> getLocation(@PathVariable String clientId) {
        Device d = deviceService.getDeviceById(clientId);
        if (d == null) {
            log.error("{} not found", clientId);
            return Mono.just(new APIResult(APICodes.UnregisteredClient));
        }
        Map<String, Object> rtn = new HashMap<>(6);
        rtn.put("clientId", clientId);
        rtn.put("locationTime", DateFormatUtils.format(d.getLocationTime(), "yyyy-MM-dd HH:mm:ss"));
        rtn.put("lng", d.getLng());
        rtn.put("lat", d.getLat());
        rtn.put("speedKph", d.getSpeedKph());
        rtn.put("electricState", d.getElectricState());
        rtn.put("electricPercent", d.getElectricPercent());
        rtn.put("electricVoltage", d.getElectricVoltage());
        rtn.put("sos", d.getSos());
        if (d.getSosTime() != null) {
            rtn.put("sosTime", DateFormatUtils.format(d.getSosTime(), "yyyy-MM-dd HH:mm:ss"));
        }
        if (log.isInfoEnabled()){
            log.info(JsonUtils.toJson(rtn));
        }
        return Mono.just(APIResult.ok(rtn));
    }

    @Operation(summary = "文本下发转TTS")
    @PostMapping("tts")
    public Mono<APIResult<T0001>> tts(@RequestParam String clientId, @RequestParam String content) {
        Device d = deviceService.getDeviceById(clientId);
        if (d == null) {
            log.error("{} is not register", clientId);
            return Mono.just(new APIResult(APICodes.UnregisteredClient));
        }
        T8300 t8300 = new T8300(content);
        t8300.setSign(8);
        t8300.setClientId(clientId);
        if (log.isInfoEnabled()) {
            log.info("{} tts : {}",clientId, content);
        }
        return T8300(t8300);
    }

    @Operation(summary = "查询终端是否在线")
    @GetMapping("online/{clientId}")
    public Mono<APIResult<Object>> online(@PathVariable String clientId) {
        Device d = deviceService.getDeviceById(clientId);
        if (d == null) {
            log.error("{} is not register", clientId);
            return Mono.just(new APIResult(APICodes.UnregisteredClient));
        }
        APIResult rtn = null;
        if (cacheUtil.get(d.getClientId()) != null) {
            rtn = new APIResult(APICodes.Success);
        }else{
            log.warn("{} is offline", clientId);
            rtn = new APIResult(APICodes.OfflineClient);
        }
        return Mono.just(rtn);
    }

    @Operation(summary = "查询终端实时位置")
    @GetMapping("position/{clientId}")
    public Mono<APIResult<T0001>> position(@PathVariable String clientId) {
        Device d = deviceService.getDeviceById(clientId);
        if (d == null) {
            log.error("{} is not register", clientId);
            return Mono.just(new APIResult(APICodes.UnregisteredClient));
        }
        APIResult rtn = null;
        if (cacheUtil.get(d.getClientId()) != null) {
            T8300 loc = new T8300("C");
            loc.setClientId(clientId);
            loc.setSign(1);
            return T8300(loc);
        }else{
            log.warn("{} is offline", clientId);
        }
        return Mono.just(new APIResult(APICodes.OfflineClient));
    }
}